查看原文
其他

.NET Core实现一个简易的事件协调器(saga)

DotNet 2021-09-23

推荐关注↓

在领域驱动设计中,由于领域边界的存在,以往的分层设计中业务会按照其固有的领域知识被切分到不同的限界中,并且引入了领域事件这一概念来降低单个业务的复杂度,通过非耦合的事件驱动来完成复杂的业务。但是事件驱动带来了一些新的问题,由于以往一个原子性极强的逻辑被拆散到了一个一个小的领域中,原子性事务数据的强一致性无法被保证。为了解决这个问题,一般会采用事务补偿的方式来确保最终一致。

事务补偿机制有多种实现方式,有基于数据库自带的基于2PC的XA协议、也有在逻辑层通过TCC实现,抑或采用多个本地事务组合的方式来实现。

当我们采用多个本地事务组合去进行业务处理时,由于业务其本身的复杂性,往往需要在多个事务中协调。而事件协调器(saga)就是一个专门降低其复杂度的设计,开发人员原则上只需要将事件和补偿按照一定顺序注册到协调处理器中,原则上协调器会按照注册的事件依次执行,若出现事件执行失败时,也会按照补偿列表进行相应的回滚。在微软其开源项目eshopcontainer中就提出了process manager概念。通过一个process manager来协调多个微服务之间的事务。

我们就通过一些简单的代码设计,来还原一个简易的基于事件总线的协调器。

废话不多说,先上代码:https://github.com/sd797994/EventCoordinator

解决方案包含两个项目(TargetFramework为.net5,如果你没有安装.net,可以改成netcoreapp3.1),一个是演示用的webapi demo。包含基本的控制器和一组事件及事件订阅处理服务。

演示项目流程如下:

客户端访问接口下订单->发布订单创建事件->订单预创建订阅处理器创建订单编号->发布订单预创建成功事件->商品扣除订阅处理器订阅订单预创建成功事件并进行商品库存扣除->发布库存扣除成功事件->用户余额扣扣除订阅处理器订阅库存扣除成功事件并执行用户余额扣除->发布用户余额扣除成功事件->订单创建订阅处理器订阅用户余额扣除成功事件创建订单。若其中每一步处理失败,则依次进行回滚。

若一切正常,则流程结果执行如下:

模拟最后一步订单创建失败时,全部回滚的结果如下:

模拟订单创建失败用户金额回滚成功商品库存回滚异常时,结果如下(在真实的业务场景中出现此类情况应该进行系统预警人工处理,我这里采用logger.error模拟警戒级别):

下面我们来看看实现思路和代码,打开EventCoordinator项目,我们可以看到事件总线/事件协调器/通用三个文件夹。其中通用类是一些帮助方法不再赘述,事件也是基于System.Threading.Channels的简易异步事件总线实现,也不再赘述。主要说说协调器。

协调器的核心主要是EventProcessManager.cs以及EventProcessManagerPipline.cs以及ProcessConfigure.cs三个文件来实现的。我的设计逻辑如下:EventProcessManager管理所有的流程性事务。

所以其包含长事务的注册和启动逻辑。而事务注册实际上就是一个构造委托代理的过程,我把它命名为ProcessConfigure,通过创建一个流程配置实例,将向EventProcessManager注册的委托作为“配置”的一部分创建其对应的方法委托,再在具体执行流程时从队列中取出配置并执行其的excute方法来发布事件,并且通过托管委托的方式在代理订阅器里执行真正的委托。

而所有的入队、入栈我创建了一个EventProcessManagerPipline实例来保存我们的ProcessConfigure,这个管道包含一个队列和一个栈,由于事件是按照先进先出的方式执行,所以事件委托创建的配置会以队列的方式保存。

而补偿则是按照先进后出的方式执行,所以补偿委托创建的配置会以栈的方式保存。

而整个管道事务流转的核心均在EventProcessManagerPipline的Start方法中。

Start的核心逻辑如下:启动一个流程,在一个while循环中 从当前的队列中弹出一个事件配置。执行事件配置的send方法,并且通过AutoResetEvent的方式阻塞等待信号。

当真正的业务委托执行完毕后会触发代理的AutoResetEvent.set(),如果业务执行callnext,则会将当前事件处理的结果作为callbackevent的一部分存储在缓存里,方便顺序回滚。如果执行callback,则直接执行回滚。如果所有的事件/补偿执行完毕,则流程执行完毕。

结语

整个代码其实比较简单,仅仅是我对长事务治理思想的一个粗浅理解,可能有误,恳请评论区大佬指正。


转自:a1010

链接:cnblogs.com/gmmy/p/14606109.html

- EOF -

推荐阅读  点击标题可跳转

.NET 简单、高效、避免OOM的Excel工具

.NET 异步,你也许不知道的5种用法

比雪花算法更好用的ID生成算法(支持C#)


看完本文有收获?请转发分享给更多人

推荐关注「DotNet」,提升.Net技能 

点赞和在看就是最大的支持❤️

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存